package com.hardson.toolkit.util;

import java.io.*;
import java.util.Objects;

public class Base64Encoder {

    public static final int BYTES_PER_ATOM = 3;

    public static final int BYTES_PER_LINE = 57;

    private final static char pad = '=';

    private static byte[] c2b = null;

    private static final char[] mapTable = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
            'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b',
            'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
            't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
            '@', '/'};

    public Base64Encoder() {
    }

    public void encode(final InputStream inputstream, final OutputStream outputstream)
            throws IOException {
        //        byte abyte0[] = System.getProperty("line.separator").getBytes();
        int i = 0;
        byte[] abyte1 = new byte[57];
        while ((i = inputstream.read(abyte1, 0, 57)) != -1) {
            for (int j = 0; j < i; j += 3) {
                if (j + 3 <= i) {
                    this.encodeAtom(outputstream, abyte1, j, 3);
                } else {
                    this.encodeAtom(outputstream, abyte1, j, i - j);
                }
            }

            //outputstream.write(abyte0);
        }
    }

    public void encode(final byte[] abyte0, final OutputStream outputstream) throws IOException {
        ByteArrayInputStream bytearrayinputstream = new ByteArrayInputStream(abyte0);
        this.encode(bytearrayinputstream, outputstream);
    }

    public String encode(final String toEncode) {
        byte[] bToEncode = null;
        ByteArrayOutputStream bo = new ByteArrayOutputStream();
        DataOutputStream dout = new DataOutputStream(bo);
        try {
            dout.write(toEncode.getBytes());
            dout.flush();
            bToEncode = bo.toByteArray();
            bo.close();
            dout.close();
        } catch (IOException e) {
            // 字节数组流不会抛出IO异常，因此封闭
        }
        return this.encode(bToEncode);
    }

    public String encode(final byte[] abyte0) {
        ByteArrayOutputStream bytearrayoutputstream = new ByteArrayOutputStream();
        ByteArrayInputStream bytearrayinputstream = new ByteArrayInputStream(abyte0);
        try {
            this.encode(bytearrayinputstream, bytearrayoutputstream);
        } catch (IOException e) {
            // 字节数据流不会抛出IO异常，因此在此封闭IO异常
        }
        return bytearrayoutputstream.toString();
    }

    protected void encodeAtom(final OutputStream outputstream, final byte[] abyte0, final int i,
                              final int j) throws IOException {
        if (j == 1) {
            byte byte0 = abyte0[i];
            int k = 0;
            //           boolean flag = false;
            outputstream.write(mapTable[byte0 >>> 2 & 0x3f]);
            outputstream.write(mapTable[(byte0 << 4 & 0x30) + (k >>> 4 & 0xf)]);
            outputstream.write(61);
            outputstream.write(61);
        } else if (j == 2) {
            byte byte1 = abyte0[i];
            byte byte3 = abyte0[i + 1];
            int l = 0;
            outputstream.write(mapTable[byte1 >>> 2 & 0x3f]);
            outputstream.write(mapTable[(byte1 << 4 & 0x30) + (byte3 >>> 4 & 0xf)]);
            outputstream.write(mapTable[(byte3 << 2 & 0x3c) + (l >>> 6 & 3)]);
            outputstream.write(61);
        } else {
            byte byte2 = abyte0[i];
            byte byte4 = abyte0[i + 1];
            byte byte5 = abyte0[i + 2];
            outputstream.write(mapTable[byte2 >>> 2 & 0x3f]);
            outputstream.write(mapTable[(byte2 << 4 & 0x30) + (byte4 >>> 4 & 0xf)]);
            outputstream.write(mapTable[(byte4 << 2 & 0x3c) + (byte5 >>> 6 & 3)]);
            outputstream.write(mapTable[byte5 & 0x3f]);
        }
    }

    public String decode(final String es) {
        if (c2b == null) {
            c2b = new byte[256];
            for (byte b = 0; b < 64; b++) {
                c2b[(byte) mapTable[b]] = b;
            }
        } // end if

        byte[] nibble = new byte[4];
        byte[] decode = new byte[es.length()];
        int d = 0;
        int n = 0;
        byte b;
        for (int i = 0; i < es.length(); i++) {
            char c = es.charAt(i);
            nibble[n] = c2b[c];

            if (c == pad) {
                break;
            }

            switch (n) {
                case 0:
                    n++;
                    break;

                case 1:
                    b = (byte) (nibble[0] * 4 + nibble[1] / 16);
                    decode[d++] = b;
                    n++;
                    break;

                case 2:
                    b = (byte) ((nibble[1] & 0xf) * 16 + nibble[2] / 4);
                    decode[d++] = b;
                    n++;
                    break;

                default:
                    b = (byte) ((nibble[2] & 0x3) * 64 + nibble[3]);
                    decode[d++] = b;
                    n = 0;
                    break;
            }
        }

        return new String(decode, 0, d);
    }

    public boolean verify(final String ds, final String es) {
        return (Objects.equals(ds, this.decode(es)));
    }

    public static void main(final String[] args) {
        Base64Encoder base64 = new Base64Encoder();
        String sEn = "";
        try {
			/*        byte[] a = {'a','b'};
			        sEn = base64.encode(a);
			        a = base64.decode(sEn).getBytes();
			        System.out.println(a[0]=='a');
			        System.out.println(a[1]=='b');
			        System.out.println(a.length );*/
            //        sEn=base64.encode("select * from doc_card 我 where a like 'u%' and a='232999'");//("select * from sadfasdfsadfhjkhkjjhklhkjlhkjhjkj where a like 'u%' and a='232999'");
            sEn = base64.encode(
                    "not (not(doc_open >=1) and not exists(select 1 as right from doc_right where user_code='hq' and doc_seq=v_doc_card.doc_seq  and right_view>0) and not exists(select '1' as right from v_dfolderright where room_id=v_doc_card.room_id and cate_room = v_doc_card.cate_room and user_code='hq' and cate_code = v_doc_card.cate_code  and view_secr >= v_doc_card.secr_code and view_keep<=v_doc_card.keep_time  and right_view>0 and doc_type = v_doc_card.arch_flag))");
            System.err.println("after encode=" + sEn);
            sEn = base64.decode(sEn);
            System.err.println("after decode=" + sEn);
            System.err.println(new String(sEn.getBytes(), "GBK"));
        } catch (Exception ex) {
        }
    }
}
